Libérez la puissance de la logique réutilisable dans vos applications React avec les hooks personnalisés. Apprenez à créer et utiliser des hooks personnalisés pour un code plus propre et plus facile à maintenir.
Hooks Personnalisés : Patrons de Logique Réutilisable dans React
Les hooks de React ont révolutionné la façon dont nous écrivons les composants React en introduisant l'état et les fonctionnalités de cycle de vie aux composants fonctionnels. Parmi les nombreux avantages qu'ils offrent, les hooks personnalisés se distinguent comme un mécanisme puissant pour extraire et réutiliser la logique entre plusieurs composants. Cet article de blog explorera en profondeur le monde des hooks personnalisés, en examinant leurs avantages, leur création et leur utilisation avec des exemples pratiques.
Que sont les Hooks Personnalisés ?
Essentiellement, un hook personnalisé est une fonction JavaScript qui commence par le mot « use » et peut appeler d'autres hooks. Ils vous permettent d'extraire la logique d'un composant dans des fonctions réutilisables. C'est un moyen puissant de partager une logique avec état (stateful), des effets de bord ou d'autres comportements complexes entre les composants sans recourir aux render props, aux composants d'ordre supérieur (HOC) ou à d'autres patrons complexes.
Caractéristiques Clés des Hooks Personnalisés :
- Convention de Nommage : Les hooks personnalisés doivent commencer par le mot « use ». Cela signale à React que la fonction contient des hooks et doit suivre les rÚgles des hooks.
- Réutilisabilité : L'objectif principal est d'encapsuler une logique réutilisable, facilitant ainsi le partage de fonctionnalités entre les composants.
- Logique avec Ătat : Les hooks personnalisĂ©s peuvent gĂ©rer leur propre Ă©tat en utilisant le hook
useState, ce qui leur permet d'encapsuler des comportements complexes avec état. - Effets de Bord : Ils peuvent également effectuer des effets de bord en utilisant le hook
useEffect, permettant l'intégration avec des API externes, la récupération de données, et plus encore. - Composabilité : Les hooks personnalisés peuvent appeler d'autres hooks, vous permettant de construire une logique complexe en composant des hooks plus petits et plus ciblés.
Avantages de l'Utilisation des Hooks Personnalisés
Les hooks personnalisés offrent plusieurs avantages significatifs dans le développement React :
- Réutilisabilité du Code : L'avantage le plus évident est la capacité de réutiliser la logique entre plusieurs composants. Cela réduit la duplication de code et favorise une base de code plus DRY (Don't Repeat Yourself).
- Lisibilité Améliorée : En extrayant la logique complexe dans des hooks personnalisés distincts, vos composants deviennent plus propres et plus faciles à comprendre. La logique principale du composant reste concentrée sur le rendu de l'interface utilisateur.
- MaintenabilitĂ© AmĂ©liorĂ©e : Lorsque la logique est encapsulĂ©e dans des hooks personnalisĂ©s, les modifications et les corrections de bugs peuvent ĂȘtre appliquĂ©es Ă un seul endroit, rĂ©duisant le risque d'introduire des erreurs dans plusieurs composants.
- TestabilitĂ© : Les hooks personnalisĂ©s peuvent ĂȘtre facilement testĂ©s de maniĂšre isolĂ©e, garantissant que la logique rĂ©utilisable fonctionne correctement indĂ©pendamment des composants qui l'utilisent.
- Composants Simplifiés : Les hooks personnalisés aident à désencombrer les composants, les rendant moins verbeux et plus concentrés sur leur objectif principal.
Créer Votre Premier Hook Personnalisé
Illustrons la crĂ©ation d'un hook personnalisĂ© avec un exemple pratique : un hook qui suit la taille de la fenĂȘtre.
Exemple : useWindowSize
Ce hook retournera la largeur et la hauteur actuelles de la fenĂȘtre du navigateur. Il mettra Ă©galement Ă jour ces valeurs lorsque la fenĂȘtre sera redimensionnĂ©e.
import { useState, useEffect } from 'react';
function useWindowSize() {
const [windowSize, setWindowSize] = useState({
width: window.innerWidth,
height: window.innerHeight,
});
useEffect(() => {
function handleResize() {
setWindowSize({
width: window.innerWidth,
height: window.innerHeight,
});
}
window.addEventListener('resize', handleResize);
// Supprimer l'écouteur d'événement au nettoyage
return () => window.removeEventListener('resize', handleResize);
}, []); // Le tableau vide assure que l'effet ne s'exécute qu'au montage
return windowSize;
}
export default useWindowSize;
Explication :
- Importer les Hooks Nécessaires : Nous importons
useStateetuseEffectde React. - Définir le Hook : Nous créons une fonction nommée
useWindowSize, en respectant la convention de nommage. - Initialiser l'Ătat : Nous utilisons
useStatepour initialiser l'Ă©tatwindowSizeavec la largeur et la hauteur initiales de la fenĂȘtre. - Mettre en Place un Ăcouteur d'ĂvĂ©nement : Nous utilisons
useEffectpour ajouter un Ă©couteur d'Ă©vĂ©nement de redimensionnement Ă la fenĂȘtre. Lorsque la fenĂȘtre est redimensionnĂ©e, la fonctionhandleResizemet Ă jour l'Ă©tatwindowSize. - Nettoyage : Nous retournons une fonction de nettoyage depuis
useEffectpour supprimer l'écouteur d'événement lorsque le composant est démonté. Cela prévient les fuites de mémoire. - Retourner les Valeurs : Le hook retourne l'objet
windowSize, contenant la largeur et la hauteur actuelles de la fenĂȘtre.
Utiliser le Hook Personnalisé dans un Composant
Maintenant que nous avons créé notre hook personnalisé, voyons comment l'utiliser dans un composant React.
import React from 'react';
import useWindowSize from './useWindowSize';
function MyComponent() {
const { width, height } = useWindowSize();
return (
Largeur de la fenĂȘtre : {width}px
Hauteur de la fenĂȘtre : {height}px
);
}
export default MyComponent;
Explication :
- Importer le Hook : Nous importons le hook personnalisé
useWindowSize. - Appeler le Hook : Nous appelons le hook
useWindowSizeà l'intérieur du composant. - Accéder aux Valeurs : Nous déstructurons l'objet retourné pour obtenir les valeurs
widthetheight. - Afficher les Valeurs : Nous affichons les valeurs de largeur et de hauteur dans l'interface utilisateur du composant.
Tout composant utilisant useWindowSize se mettra automatiquement Ă jour lorsque la taille de la fenĂȘtre changera.
Exemples Plus Complexes
Explorons quelques cas d'utilisation plus avancés pour les hooks personnalisés.
Exemple : useLocalStorage
Ce hook vous permet de stocker et de récupérer facilement des données du stockage local.
import { useState, useEffect } from 'react';
function useLocalStorage(key, initialValue) {
// Ătat pour stocker notre valeur
// Passer la valeur initiale à useState pour que la logique ne soit exécutée qu'une fois
const [storedValue, setStoredValue] = useState(() => {
try {
// Obtenir depuis le stockage local par clé
const item = window.localStorage.getItem(key);
// Analyser le JSON stocké ou retourner initialValue s'il n'y en a pas
return item ? JSON.parse(item) : initialValue;
} catch (error) {
// En cas d'erreur, retourner également initialValue
console.log(error);
return initialValue;
}
});
// Retourner une version encapsulée de la fonction setter de useState qui...
// ... persiste la nouvelle valeur dans localStorage.
const setValue = (value) => {
try {
// Permettre Ă la valeur d'ĂȘtre une fonction pour avoir la mĂȘme API que useState
const valueToStore = value instanceof Function ? value(storedValue) : value;
// Sauvegarder dans le stockage local
window.localStorage.setItem(key, JSON.stringify(valueToStore));
// Sauvegarder l'état
setStoredValue(valueToStore);
} catch (error) {
// Une implémentation plus avancée gérerait le cas d'erreur
console.log(error);
}
};
useEffect(() => {
try {
const item = window.localStorage.getItem(key);
setStoredValue(item ? JSON.parse(item) : initialValue);
} catch (error) {
console.log(error);
}
}, [key, initialValue]);
return [storedValue, setValue];
}
export default useLocalStorage;
Utilisation :
import React from 'react';
import useLocalStorage from './useLocalStorage';
function MyComponent() {
const [name, setName] = useLocalStorage('name', 'Invité');
return (
Bonjour, {name} !
setName(e.target.value)}
/>
);
}
export default MyComponent;
Exemple : useFetch
Ce hook encapsule la logique de récupération de données depuis une API.
import { useState, useEffect } from 'react';
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function fetchData() {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Erreur HTTP ! statut : ${response.status}`);
}
const json = await response.json();
setData(json);
setLoading(false);
} catch (error) {
setError(error);
setLoading(false);
}
}
fetchData();
}, [url]);
return { data, loading, error };
}
export default useFetch;
Utilisation :
import React from 'react';
import useFetch from './useFetch';
function MyComponent() {
const { data, loading, error } = useFetch('https://jsonplaceholder.typicode.com/todos/1');
if (loading) return Chargement...
;
if (error) return Erreur : {error.message}
;
return (
Titre : {data.title}
Terminé : {data.completed ? 'Oui' : 'Non'}
);
}
export default MyComponent;
Meilleures Pratiques pour les Hooks Personnalisés
Pour garantir que vos hooks personnalisés sont efficaces et maintenables, suivez ces meilleures pratiques :
- Gardez-les CiblĂ©s : Chaque hook personnalisĂ© doit avoir un seul objectif bien dĂ©fini. Ăvitez de crĂ©er des hooks trop complexes qui essaient d'en faire trop.
- Documentez Vos Hooks : Fournissez une documentation claire et concise pour chaque hook personnalisé, expliquant son objectif, ses entrées et ses sorties.
- Testez Vos Hooks : Rédigez des tests unitaires pour vos hooks personnalisés afin de vous assurer qu'ils fonctionnent correctement et de maniÚre fiable.
- Utilisez des Noms Descriptifs : Choisissez des noms descriptifs pour vos hooks personnalisés qui indiquent clairement leur objectif.
- GĂ©rez les Erreurs avec ĂlĂ©gance : ImplĂ©mentez la gestion des erreurs dans vos hooks personnalisĂ©s pour Ă©viter les comportements inattendus et fournir des messages d'erreur informatifs.
- Pensez Ă la RĂ©utilisabilitĂ© : Concevez vos hooks personnalisĂ©s en gardant la rĂ©utilisabilitĂ© Ă l'esprit. Rendez-les suffisamment gĂ©nĂ©riques pour ĂȘtre utilisĂ©s dans plusieurs composants.
- Ăvitez la Sur-Abstraction : Ne crĂ©ez pas de hooks personnalisĂ©s pour une logique simple qui peut ĂȘtre facilement gĂ©rĂ©e au sein d'un composant. N'extrayez que la logique qui est vraiment rĂ©utilisable et complexe.
PiĂšges Courants Ă Ăviter
- Enfreindre les RÚgles des Hooks : Appelez toujours les hooks au niveau supérieur de votre fonction de hook personnalisé et ne les appelez que depuis des composants fonctionnels React ou d'autres hooks personnalisés.
- Ignorer les Dépendances dans useEffect : Assurez-vous d'inclure toutes les dépendances nécessaires dans le tableau de dépendances du hook
useEffectpour éviter les fermetures (closures) obsolÚtes et les comportements inattendus. - Créer des Boucles Infinies : Soyez prudent lorsque vous mettez à jour l'état dans un hook
useEffect, car cela peut facilement conduire à des boucles infinies. Assurez-vous que la mise à jour est conditionnelle et basée sur les changements de dépendances. - Oublier le Nettoyage : Incluez toujours une fonction de nettoyage dans
useEffectpour supprimer les écouteurs d'événements, annuler les abonnements et effectuer d'autres tùches de nettoyage pour éviter les fuites de mémoire.
Patrons Avancés
Composer des Hooks Personnalisés
Les hooks personnalisĂ©s peuvent ĂȘtre composĂ©s ensemble pour crĂ©er une logique plus complexe. Par exemple, vous pourriez combiner un hook useLocalStorage avec un hook useFetch pour persister automatiquement les donnĂ©es rĂ©cupĂ©rĂ©es dans le stockage local.
Partager la Logique entre les Hooks
Si plusieurs hooks personnalisés partagent une logique commune, vous pouvez extraire cette logique dans une fonction utilitaire distincte et la réutiliser dans les deux hooks.
Utiliser le Contexte avec les Hooks Personnalisés
Les hooks personnalisĂ©s peuvent ĂȘtre utilisĂ©s en conjonction avec le Contexte de React pour accĂ©der et mettre Ă jour l'Ă©tat global. Cela vous permet de crĂ©er des composants rĂ©utilisables qui sont conscients de l'Ă©tat global de l'application et peuvent interagir avec lui.
Exemples du Monde Réel
Voici quelques exemples de la façon dont les hooks personnalisĂ©s peuvent ĂȘtre utilisĂ©s dans des applications du monde rĂ©el :
- Validation de Formulaire : Créez un hook
useFormpour gérer l'état, la validation et la soumission du formulaire. - Authentification : Implémentez un hook
useAuthpour gérer l'authentification et l'autorisation des utilisateurs. - Gestion de ThÚme : Développez un hook
useThemepour basculer entre différents thÚmes (clair, sombre, etc.). - Géolocalisation : Construisez un hook
useGeolocationpour suivre la position actuelle de l'utilisateur. - Détection de Défilement : Créez un hook
useScrollpour détecter lorsque l'utilisateur a défilé jusqu'à un certain point de la page.
Exemple : hook useGeolocation pour les applications interculturelles comme les services de cartographie ou de livraison
import { useState, useEffect } from 'react';
function useGeolocation() {
const [location, setLocation] = useState({
latitude: null,
longitude: null,
error: null,
});
useEffect(() => {
if (!navigator.geolocation) {
setLocation({
latitude: null,
longitude: null,
error: 'La géolocalisation n\'est pas prise en charge par ce navigateur.',
});
return;
}
const watchId = navigator.geolocation.watchPosition(
(position) => {
setLocation({
latitude: position.coords.latitude,
longitude: position.coords.longitude,
error: null,
});
},
(error) => {
setLocation({
latitude: null,
longitude: null,
error: error.message,
});
}
);
return () => navigator.geolocation.clearWatch(watchId);
}, []);
return location;
}
export default useGeolocation;
Conclusion
Les hooks personnalisés sont un outil puissant pour écrire du code React plus propre, plus réutilisable et plus maintenable. En encapsulant la logique complexe dans des hooks personnalisés, vous pouvez simplifier vos composants, réduire la duplication de code et améliorer la structure globale de vos applications. Adoptez les hooks personnalisés et libérez leur potentiel pour construire des applications React plus robustes et évolutives.
Commencez par identifier les zones de votre base de code existante oĂč la logique est rĂ©pĂ©tĂ©e entre plusieurs composants. Ensuite, refactorisez cette logique en hooks personnalisĂ©s. Au fil du temps, vous construirez une bibliothĂšque de hooks rĂ©utilisables qui accĂ©lĂ©rera votre processus de dĂ©veloppement et amĂ©liorera la qualitĂ© de votre code.
N'oubliez pas de suivre les meilleures pratiques, d'éviter les piÚges courants et d'explorer les patrons avancés pour tirer le meilleur parti des hooks personnalisés. Avec de la pratique et de l'expérience, vous deviendrez un maßtre des hooks personnalisés et un développeur React plus efficace.